package model

import "sync"

type SyncQueue struct {
	cond *sync.Cond
	w    *node
	r    *node
}

func NewSyncQueue() *SyncQueue {
	return &SyncQueue{
		cond: sync.NewCond(&sync.Mutex{}),
	}
}

func (q *SyncQueue) Push(data interface{}) {
	q.cond.L.Lock()
	n := &node{
		data: data,
		next: nil,
	}
	if q.w != nil {
		q.w.next = n
	}
	q.w = n
	if q.r == nil {
		q.r = q.w
	}
	q.cond.L.Unlock()
	q.cond.Signal()
}

func (q *SyncQueue) Pop() interface{} {
	q.cond.L.Lock()
	for q.r == nil {
		q.cond.Wait()
	}
	data := q.r.data
	q.r = q.r.next
	q.cond.L.Unlock()
	return data
}

type node struct {
	data interface{}
	next *node
}
